﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using FMOD;

namespace LaunchPad.Core.Controls.Tracks
{
    public class AudioTimeControlBase : UserControl
    {
        public static readonly DependencyProperty TrackProperty = DependencyProperty.RegisterAttached(
            "AudioTrack", typeof (AudioTrack), typeof (AudioTimeControlBase),
            new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits, OnTrackChanged));

        public static readonly DependencyProperty ZoomFactorProperty = DependencyProperty.RegisterAttached(
            "ZoomFactor", typeof (double), typeof (AudioTimeControlBase),
            new FrameworkPropertyMetadata(2.0, FrameworkPropertyMetadataOptions.Inherits, OnZoomFactorChanged));

        public static readonly RoutedEvent BeginCueHelperMoveEvent = EventManager.RegisterRoutedEvent(
            "BeginCueHelperMove", RoutingStrategy.Bubble, typeof (RoutedEventHandler), typeof (AudioTimeControlBase));

        public static readonly RoutedEvent CueHelperMoveEvent = EventManager.RegisterRoutedEvent(
            "CueHelperMove", RoutingStrategy.Bubble, typeof (RoutedEventHandler), typeof (AudioTimeControlBase));

        public static readonly RoutedEvent EndCueHelperMoveEvent = EventManager.RegisterRoutedEvent(
            "EndCueHelperMove", RoutingStrategy.Bubble, typeof (RoutedEventHandler), typeof (AudioTimeControlBase));

        public AudioTimeControlBase()
        {
            TimePositionConverter = new TimePositionConverter();
        }

        protected TimePositionConverter TimePositionConverter { get; set; }

        public AudioTrack AudioTrack
        {
            get { return (AudioTrack) GetValue(TrackProperty); }
            set { SetValue(TrackProperty, value); }
        }

        public bool IsAudioLoaded
        {
            get { return AudioTrack != null; }
        }

        public TimeSpan PlaybackPosition
        {
            get { return AudioTrack.Position; }
            set
            {
                if (IsAudioLoaded && value < AudioTrack.Length && value > TimeSpan.Zero)
                    AudioTrack.Position = value;
            }
        }

        public double ZoomFactor
        {
            get { return (double) GetValue(ZoomFactorProperty); }
            set { SetValue(ZoomFactorProperty, value); }
        }

        public TimeSpan Length
        {
            get
            {
                if (AudioTrack == null)
                    return TimeSpan.Zero;

                return AudioTrack.Length;
            }
        }

        public double AudioWidth
        {
            get { return ConvertFromTime(Length); }
        }

        public event EventHandler<PlaybackPositionEventArgs> PositionChanged;

        public event RoutedEventHandler BeginCueHelperMove
        {
            add { AddHandler(BeginCueHelperMoveEvent, value); }
            remove { RemoveHandler(BeginCueHelperMoveEvent, value); }
        }

        public event RoutedEventHandler CueHelperMove
        {
            add { AddHandler(CueHelperMoveEvent, value); }
            remove { RemoveHandler(CueHelperMoveEvent, value); }
        }

        public event RoutedEventHandler EndCueHelperMove
        {
            add { AddHandler(EndCueHelperMoveEvent, value); }
            remove { RemoveHandler(EndCueHelperMoveEvent, value); }
        }

        protected virtual void OnBeginCueHelperMove()
        {
            var args = new RoutedEventArgs(BeginCueHelperMoveEvent);
            RaiseEvent(args);
        }

        protected virtual void OnCueHelperMove(TimeSpan position)
        {
            var args = new CueHelperMoveRoutedEventArgs(CueHelperMoveEvent, position);
            RaiseEvent(args);
        }

        protected virtual void OnEndCueHelperMove()
        {
            var args = new RoutedEventArgs(EndCueHelperMoveEvent);
            RaiseEvent(args);
        }

        private static void OnTrackChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            var control = sender as AudioTimeControlBase;

            if (control != null)
            {
                var track = (AudioTrack) e.NewValue;

                if (track != null)
                {
                    control.TimePositionConverter.Track = track;
                    control.OnTrackChanged(e);
                    track.PositionChanged += control.TrackPositionChanged;
                }
            }
        }

        private void TrackPositionChanged(object sender, EventArgs e)
        {
            if (PositionChanged != null)
            {
                Dispatcher.BeginInvoke(DispatcherPriority.Normal,
                                       (Action)delegate
                                       {
                                           if (AudioTrack != null)
                                           {
                                               PositionChanged(this,
                                                               new PlaybackPositionEventArgs(
                                                                   AudioTrack.Position,
                                                                   TimePositionConverter.GetPosition(
                                                                       AudioTrack.Position)));
                                           }
                                       });
            }
        }

        protected virtual void OnTrackChanged(DependencyPropertyChangedEventArgs e)
        {
        }

        private static void OnZoomFactorChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            var control = sender as AudioTimeControlBase;

            if (control != null)
            {
                control.TimePositionConverter.ZoomFactor = (double) e.NewValue;
                control.OnZoomFactorChanged(e);
            }
        }

        protected virtual void OnZoomFactorChanged(DependencyPropertyChangedEventArgs e)
        {
        }

        protected TimeSpan ConvertFromPosition(double position)
        {
            if (TimePositionConverter == null)
                return TimeSpan.Zero;

            return TimePositionConverter.GetTime(position);
        }

        protected double ConvertFromTime(TimeSpan time)
        {
            if (TimePositionConverter == null)
                return 0;

            return TimePositionConverter.GetPosition(time);
        }
    }
}